using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using Microsoft.Dss.ServiceModel.DsspServiceBase;
using W3C.Soap;

using submgr = Microsoft.Dss.Services.SubscriptionManager;
using vision = HCC.Robotics.Services.HCCGenericVisionModule.Proxy;

// For Forms
using Microsoft.Ccr.Adapters.WinForms;
using System.Windows.Forms;
// For handling Web images
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
// Webcam
using webcam = Microsoft.Robotics.Services.WebCam.Proxy;
using Microsoft.Dss.Services.ControlPanel;

namespace HCC.Robotics.HCCVisionModule
{
    [Contract(Contract.Identifier)]
    [DisplayName("HCCVisionModule")]
    [Description("HCCVisionModule service.\nProvides real webcam data of the soccer field.")]
    [AlternateContract(vision.Contract.Identifier)]
    class HCCVisionModuleService : DsspServiceBase
    {
        // This port receives events from the user interface
        FromWinformEvents _fromWinformPort = new FromWinformEvents();

        // This is the stateengine state of the service
        Status _currentState = Status.Calibrarting;

        // this is data to be send.
        vision.VisionData _visionData = new vision.VisionData();

        [ServiceState]
        vision.HCCGenericVisionModuleState _state = new vision.HCCGenericVisionModuleState();

        [ServicePort("/HCCVisionModule", AllowMultipleInstances = false)]
        vision.HCCGenericVisionModuleOperations _mainPort = new vision.HCCGenericVisionModuleOperations();

        [Partner("FieldCam", Contract = webcam.Contract.Identifier, CreationPolicy = PartnerCreationPolicy.UseExistingOrCreate, Optional = false)]
        webcam.WebCamOperations _cameraPort = new webcam.WebCamOperations();

        [SubscriptionManagerPartner]
        submgr.SubscriptionManagerPort _submgrPort = new submgr.SubscriptionManagerPort();

        public HCCVisionModuleService(DsspServiceCreationPort creationPort)
            : base(creationPort)
        {
        }

        protected override void Start()
        {
            // validate the data
            _visionData.Valid = false;
            if (_currentState == Status.Calibrarting)
            {
                // check
            }

            base.Start();

            // Add the Winform message handler to the interleave
            MainPortInterleave.CombineWith(new Interleave(
                new TeardownReceiverGroup(),
                new ExclusiveReceiverGroup
                    (
                        Arbiter.Receive<FromWinformMsg>(true, _fromWinformPort, OnWinformMessageHandler)
                    ),
                new ConcurrentReceiverGroup()
            ));

            // Create the calibration interface form
            WinFormsServicePort.Post(new RunForm(CreateForm));

            SpawnIterator(MainLoop);
        }

        System.Windows.Forms.Form CreateForm()
        {
            return new CameraCalibration(_fromWinformPort);
        }

        CameraCalibration _UI = null;

        void OnWinformMessageHandler(FromWinformMsg msg)
        {
            switch (msg.Command)
            {
                case FromWinformMsg.MsgEnum.Loaded:
                    // The windows form is ready to go
                    _UI = (CameraCalibration)msg.Object;
                    break;
                case FromWinformMsg.MsgEnum.Calibrating:
                    _currentState = Status.Calibrarting;
                    break;
                case FromWinformMsg.MsgEnum.DataCalibrated:
                    _currentState = Status.Calibrated;
                    break;
                case FromWinformMsg.MsgEnum.Shutdown:
                    ControlPanelPort.Post(new DropProcess());
                    break;
            }
        }

        IEnumerator<ITask> MainLoop()
        {
            while (true)
            {
                yield return Arbiter.Choice(
                    _cameraPort.QueryFrame(),
                    ValidateFrameHandler,
                    DefaultFaultHandler);

                yield return Arbiter.Receive(false, TimeoutPort(200), delegate { });
            }
        }

        void DefaultFaultHandler(Fault fault)
        {
            LogError(fault);
        }

        void ValidateFrameHandler(webcam.QueryFrameResponse cameraFrame)
        {
            try
            {
                if (cameraFrame.Frame != null)
                {
                    if (cameraFrame.Size.Width == 640 && cameraFrame.Size.Height == 480)
                    {
                        WinFormsServicePort.FormInvoke(
                            delegate()
                            {
                                _UI.SetCameraImage(cameraFrame.Frame, _visionData);
                            }
                        );
                    }
                    else
                    {
                        WinFormsServicePort.FormInvoke(
                            delegate()
                            {
                                _UI.SetErrorImage(cameraFrame.Size);
                            }
                        );
                    }
                }
            }
            catch (Exception ex)
            {
                LogError(ex);
            }

            vision.VisionDataUpdate visupdate = new vision.VisionDataUpdate(new vision.VisionDataUpdateRequest());
            visupdate.Body.Data = _visionData;
            _mainPort.Post(visupdate);
        }

        [ServiceHandler]
        public void SubscribeHandler(vision.Subscribe subscribe)
        {
            SubscribeHelper(_submgrPort, subscribe.Body, subscribe.ResponsePort);
        }

        [ServiceHandler]
        public void VisionDataUpdateHandler(vision.VisionDataUpdate visiondataupdate)
        {
            SendNotification(_submgrPort, visiondataupdate);
            visiondataupdate.ResponsePort.Post(DefaultUpdateResponseType.Instance);
        }
    }
}


